package com.brzjomo.secretiveworld.object.block;

import java.util.Random;
import java.util.stream.Stream;

import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.HorizontalBlock;
import net.minecraft.block.IWaterLoggable;
import net.minecraft.block.material.PushReaction;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.Fluids;
import net.minecraft.fluid.IFluidState;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.pathfinding.PathType;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.DirectionProperty;
import net.minecraft.state.EnumProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.state.properties.Half;
import net.minecraft.state.properties.StairsShape;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.Mirror;
import net.minecraft.util.Rotation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.shapes.IBooleanFunction;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.world.Explosion;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;

public class SlopeBlock extends Block implements IWaterLoggable {
	public static final DirectionProperty FACING = HorizontalBlock.HORIZONTAL_FACING;
	public static final EnumProperty<Half> HALF = BlockStateProperties.HALF;
	public static final EnumProperty<StairsShape> SHAPE = BlockStateProperties.STAIRS_SHAPE;
	public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;

	protected static final VoxelShape SHAPE_N = Stream
			.of(Block.makeCuboidShape(0, 0, 0, 16, 1, 16), Block.makeCuboidShape(0, 1, 1, 16, 2, 16),
					Block.makeCuboidShape(0, 2, 2, 16, 3, 16), Block.makeCuboidShape(0, 3, 3, 16, 4, 16),
					Block.makeCuboidShape(0, 4, 4, 16, 5, 16), Block.makeCuboidShape(0, 5, 5, 16, 6, 16),
					Block.makeCuboidShape(0, 6, 6, 16, 7, 16), Block.makeCuboidShape(0, 7, 7, 16, 8, 16),
					Block.makeCuboidShape(0, 8, 8, 16, 9, 16), Block.makeCuboidShape(0, 9, 9, 16, 10, 16),
					Block.makeCuboidShape(0, 10, 10, 16, 11, 16), Block.makeCuboidShape(0, 11, 11, 16, 12, 16),
					Block.makeCuboidShape(0, 12, 12, 16, 13, 16), Block.makeCuboidShape(0, 13, 13, 16, 14, 16),
					Block.makeCuboidShape(0, 14, 14, 16, 15, 16), Block.makeCuboidShape(0, 15, 15, 16, 16, 16))
			.reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_W = Stream
			.of(Block.makeCuboidShape(0, 0, 0, 16, 1, 16), Block.makeCuboidShape(1, 1, 0, 16, 2, 16),
					Block.makeCuboidShape(2, 2, 0, 16, 3, 16), Block.makeCuboidShape(3, 3, 0, 16, 4, 16),
					Block.makeCuboidShape(4, 4, 0, 16, 5, 16), Block.makeCuboidShape(5, 5, 0, 16, 6, 16),
					Block.makeCuboidShape(6, 6, 0, 16, 7, 16), Block.makeCuboidShape(7, 7, 0, 16, 8, 16),
					Block.makeCuboidShape(8, 8, 0, 16, 9, 16), Block.makeCuboidShape(9, 9, 0, 16, 10, 16),
					Block.makeCuboidShape(10, 10, 0, 16, 11, 16), Block.makeCuboidShape(11, 11, 0, 16, 12, 16),
					Block.makeCuboidShape(12, 12, 0, 16, 13, 16), Block.makeCuboidShape(13, 13, 0, 16, 14, 16),
					Block.makeCuboidShape(14, 14, 0, 16, 15, 16), Block.makeCuboidShape(15, 15, 0, 16, 16, 16))
			.reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_S = Stream
			.of(Block.makeCuboidShape(0, 0, 0, 16, 1, 16), Block.makeCuboidShape(0, 1, 0, 16, 2, 15),
					Block.makeCuboidShape(0, 2, 0, 16, 3, 14), Block.makeCuboidShape(0, 3, 0, 16, 4, 13),
					Block.makeCuboidShape(0, 4, 0, 16, 5, 12), Block.makeCuboidShape(0, 5, 0, 16, 6, 11),
					Block.makeCuboidShape(0, 6, 0, 16, 7, 10), Block.makeCuboidShape(0, 7, 0, 16, 8, 9),
					Block.makeCuboidShape(0, 8, 0, 16, 9, 8), Block.makeCuboidShape(0, 9, 0, 16, 10, 7),
					Block.makeCuboidShape(0, 10, 0, 16, 11, 6), Block.makeCuboidShape(0, 11, 0, 16, 12, 5),
					Block.makeCuboidShape(0, 12, 0, 16, 13, 4), Block.makeCuboidShape(0, 13, 0, 16, 14, 3),
					Block.makeCuboidShape(0, 14, 0, 16, 15, 2), Block.makeCuboidShape(0, 15, 0, 16, 16, 1))
			.reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_E = Stream
			.of(Block.makeCuboidShape(0, 0, 0, 16, 1, 16), Block.makeCuboidShape(0, 1, 0, 15, 2, 16),
					Block.makeCuboidShape(0, 2, 0, 14, 3, 16), Block.makeCuboidShape(0, 3, 0, 13, 4, 16),
					Block.makeCuboidShape(0, 4, 0, 12, 5, 16), Block.makeCuboidShape(0, 5, 0, 11, 6, 16),
					Block.makeCuboidShape(0, 6, 0, 10, 7, 16), Block.makeCuboidShape(0, 7, 0, 9, 8, 16),
					Block.makeCuboidShape(0, 8, 0, 8, 9, 16), Block.makeCuboidShape(0, 9, 0, 7, 10, 16),
					Block.makeCuboidShape(0, 10, 0, 6, 11, 16), Block.makeCuboidShape(0, 11, 0, 5, 12, 16),
					Block.makeCuboidShape(0, 12, 0, 4, 13, 16), Block.makeCuboidShape(0, 13, 0, 3, 14, 16),
					Block.makeCuboidShape(0, 14, 0, 2, 15, 16), Block.makeCuboidShape(0, 15, 0, 1, 16, 16))
			.reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_NW = Stream
			.of(Block.makeCuboidShape(0, 0, 0, 16, 1, 16), Block.makeCuboidShape(1, 1, 1, 16, 2, 16),
					Block.makeCuboidShape(2, 2, 2, 16, 3, 16), Block.makeCuboidShape(3, 3, 3, 16, 4, 16),
					Block.makeCuboidShape(4, 4, 4, 16, 5, 16), Block.makeCuboidShape(5, 5, 5, 16, 6, 16),
					Block.makeCuboidShape(6, 6, 6, 16, 7, 16), Block.makeCuboidShape(7, 7, 7, 16, 8, 16),
					Block.makeCuboidShape(8, 8, 8, 16, 9, 16), Block.makeCuboidShape(9, 9, 9, 16, 10, 16),
					Block.makeCuboidShape(10, 10, 10, 16, 11, 16), Block.makeCuboidShape(11, 11, 11, 16, 12, 16),
					Block.makeCuboidShape(12, 12, 12, 16, 13, 16), Block.makeCuboidShape(13, 13, 13, 16, 14, 16),
					Block.makeCuboidShape(14, 14, 14, 16, 15, 16), Block.makeCuboidShape(15, 15, 15, 16, 16, 16))
			.reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_NE = Stream
			.of(Block.makeCuboidShape(0, 0, 0, 16, 1, 16), Block.makeCuboidShape(0, 1, 1, 15, 2, 16),
					Block.makeCuboidShape(0, 2, 2, 14, 3, 16), Block.makeCuboidShape(0, 3, 3, 13, 4, 16),
					Block.makeCuboidShape(0, 4, 4, 12, 5, 16), Block.makeCuboidShape(0, 5, 5, 11, 6, 16),
					Block.makeCuboidShape(0, 6, 6, 10, 7, 16), Block.makeCuboidShape(0, 7, 7, 9, 8, 16),
					Block.makeCuboidShape(0, 8, 8, 8, 9, 16), Block.makeCuboidShape(0, 9, 9, 7, 10, 16),
					Block.makeCuboidShape(0, 10, 10, 6, 11, 16), Block.makeCuboidShape(0, 11, 11, 5, 12, 16),
					Block.makeCuboidShape(0, 12, 12, 4, 13, 16), Block.makeCuboidShape(0, 13, 13, 3, 14, 16),
					Block.makeCuboidShape(0, 14, 14, 2, 15, 16), Block.makeCuboidShape(0, 15, 15, 1, 16, 16))
			.reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_SW = Stream
			.of(Block.makeCuboidShape(0, 0, 0, 16, 1, 16), Block.makeCuboidShape(1, 1, 0, 16, 2, 15),
					Block.makeCuboidShape(2, 2, 0, 16, 3, 14), Block.makeCuboidShape(3, 3, 0, 16, 4, 13),
					Block.makeCuboidShape(4, 4, 0, 16, 5, 12), Block.makeCuboidShape(5, 5, 0, 16, 6, 11),
					Block.makeCuboidShape(6, 6, 0, 16, 7, 10), Block.makeCuboidShape(7, 7, 0, 16, 8, 9),
					Block.makeCuboidShape(8, 8, 0, 16, 9, 8), Block.makeCuboidShape(9, 9, 0, 16, 10, 7),
					Block.makeCuboidShape(10, 10, 0, 16, 11, 6), Block.makeCuboidShape(11, 11, 0, 16, 12, 5),
					Block.makeCuboidShape(12, 12, 0, 16, 13, 4), Block.makeCuboidShape(13, 13, 0, 16, 14, 3),
					Block.makeCuboidShape(14, 14, 0, 16, 15, 2), Block.makeCuboidShape(15, 15, 0, 16, 16, 1))
			.reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_SE = Stream
			.of(Block.makeCuboidShape(0, 0, 0, 16, 1, 16), Block.makeCuboidShape(0, 1, 0, 15, 2, 15),
					Block.makeCuboidShape(0, 2, 0, 14, 3, 14), Block.makeCuboidShape(0, 3, 0, 13, 4, 13),
					Block.makeCuboidShape(0, 4, 0, 12, 5, 12), Block.makeCuboidShape(0, 5, 0, 11, 6, 11),
					Block.makeCuboidShape(0, 6, 0, 10, 7, 10), Block.makeCuboidShape(0, 7, 0, 9, 8, 9),
					Block.makeCuboidShape(0, 8, 0, 8, 9, 8), Block.makeCuboidShape(0, 9, 0, 7, 10, 7),
					Block.makeCuboidShape(0, 10, 0, 6, 11, 6), Block.makeCuboidShape(0, 11, 0, 5, 12, 5),
					Block.makeCuboidShape(0, 12, 0, 4, 13, 4), Block.makeCuboidShape(0, 13, 0, 3, 14, 3),
					Block.makeCuboidShape(0, 14, 0, 2, 15, 2), Block.makeCuboidShape(0, 15, 0, 1, 16, 1))
			.reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_N_T = Stream
			.of(Block.makeCuboidShape(0, 15, 0, 16, 16, 16), Block.makeCuboidShape(0, 14, 1, 16, 15, 16),
					Block.makeCuboidShape(0, 13, 2, 16, 14, 16), Block.makeCuboidShape(0, 12, 3, 16, 13, 16),
					Block.makeCuboidShape(0, 11, 4, 16, 12, 16), Block.makeCuboidShape(0, 10, 5, 16, 11, 16),
					Block.makeCuboidShape(0, 9, 6, 16, 10, 16), Block.makeCuboidShape(0, 8, 7, 16, 9, 16),
					Block.makeCuboidShape(0, 7, 8, 16, 8, 16), Block.makeCuboidShape(0, 6, 9, 16, 7, 16),
					Block.makeCuboidShape(0, 5, 10, 16, 6, 16), Block.makeCuboidShape(0, 4, 11, 16, 5, 16),
					Block.makeCuboidShape(0, 3, 12, 16, 4, 16), Block.makeCuboidShape(0, 2, 13, 16, 3, 16),
					Block.makeCuboidShape(0, 1, 14, 16, 2, 16), Block.makeCuboidShape(0, 0, 15, 16, 1, 16))
			.reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_W_T = Stream
			.of(Block.makeCuboidShape(0, 15, 0, 16, 16, 16), Block.makeCuboidShape(1, 14, 0, 16, 15, 16),
					Block.makeCuboidShape(2, 13, 0, 16, 14, 16), Block.makeCuboidShape(3, 12, 0, 16, 13, 16),
					Block.makeCuboidShape(4, 11, 0, 16, 12, 16), Block.makeCuboidShape(5, 10, 0, 16, 11, 16),
					Block.makeCuboidShape(6, 9, 0, 16, 10, 16), Block.makeCuboidShape(7, 8, 0, 16, 9, 16),
					Block.makeCuboidShape(8, 7, 0, 16, 8, 16), Block.makeCuboidShape(9, 6, 0, 16, 7, 16),
					Block.makeCuboidShape(10, 5, 0, 16, 6, 16), Block.makeCuboidShape(11, 4, 0, 16, 5, 16),
					Block.makeCuboidShape(12, 3, 0, 16, 4, 16), Block.makeCuboidShape(13, 2, 0, 16, 3, 16),
					Block.makeCuboidShape(14, 1, 0, 16, 2, 16), Block.makeCuboidShape(15, 0, 0, 16, 1, 16))
			.reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_S_T = Stream
			.of(Block.makeCuboidShape(0, 15, 0, 16, 16, 16), Block.makeCuboidShape(0, 14, 0, 16, 15, 15),
					Block.makeCuboidShape(0, 13, 0, 16, 14, 14), Block.makeCuboidShape(0, 12, 0, 16, 13, 13),
					Block.makeCuboidShape(0, 11, 0, 16, 12, 12), Block.makeCuboidShape(0, 10, 0, 16, 11, 11),
					Block.makeCuboidShape(0, 9, 0, 16, 10, 10), Block.makeCuboidShape(0, 8, 0, 16, 9, 9),
					Block.makeCuboidShape(0, 7, 0, 16, 8, 8), Block.makeCuboidShape(0, 6, 0, 16, 7, 7),
					Block.makeCuboidShape(0, 5, 0, 16, 6, 6), Block.makeCuboidShape(0, 4, 0, 16, 5, 5),
					Block.makeCuboidShape(0, 3, 0, 16, 4, 4), Block.makeCuboidShape(0, 2, 0, 16, 3, 3),
					Block.makeCuboidShape(0, 1, 0, 16, 2, 2), Block.makeCuboidShape(0, 0, 0, 16, 1, 1))
			.reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_E_T = Stream
			.of(Block.makeCuboidShape(0, 15, 0, 16, 16, 16), Block.makeCuboidShape(0, 14, 0, 15, 15, 16),
					Block.makeCuboidShape(0, 13, 0, 14, 14, 16), Block.makeCuboidShape(0, 12, 0, 13, 13, 16),
					Block.makeCuboidShape(0, 11, 0, 12, 12, 16), Block.makeCuboidShape(0, 10, 0, 11, 11, 16),
					Block.makeCuboidShape(0, 9, 0, 10, 10, 16), Block.makeCuboidShape(0, 8, 0, 9, 9, 16),
					Block.makeCuboidShape(0, 7, 0, 8, 8, 16), Block.makeCuboidShape(0, 6, 0, 7, 7, 16),
					Block.makeCuboidShape(0, 5, 0, 6, 6, 16), Block.makeCuboidShape(0, 4, 0, 5, 5, 16),
					Block.makeCuboidShape(0, 3, 0, 4, 4, 16), Block.makeCuboidShape(0, 2, 0, 3, 3, 16),
					Block.makeCuboidShape(0, 1, 0, 2, 2, 16), Block.makeCuboidShape(0, 0, 0, 1, 1, 16))
			.reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_NW_T = Stream
			.of(Block.makeCuboidShape(0, 15, 0, 16, 16, 16), Block.makeCuboidShape(1, 14, 1, 16, 15, 16),
					Block.makeCuboidShape(2, 13, 2, 16, 14, 16), Block.makeCuboidShape(3, 12, 3, 16, 13, 16),
					Block.makeCuboidShape(4, 11, 4, 16, 12, 16), Block.makeCuboidShape(5, 10, 5, 16, 11, 16),
					Block.makeCuboidShape(6, 9, 6, 16, 10, 16), Block.makeCuboidShape(7, 8, 7, 16, 9, 16),
					Block.makeCuboidShape(8, 7, 8, 16, 8, 16), Block.makeCuboidShape(9, 6, 9, 16, 7, 16),
					Block.makeCuboidShape(10, 5, 10, 16, 6, 16), Block.makeCuboidShape(11, 4, 11, 16, 5, 16),
					Block.makeCuboidShape(12, 3, 12, 16, 4, 16), Block.makeCuboidShape(13, 2, 13, 16, 3, 16),
					Block.makeCuboidShape(14, 1, 14, 16, 2, 16), Block.makeCuboidShape(15, 0, 15, 16, 1, 16))
			.reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_NE_T = Stream
			.of(Block.makeCuboidShape(0, 15, 0, 16, 16, 16), Block.makeCuboidShape(0, 14, 1, 15, 15, 16),
					Block.makeCuboidShape(0, 13, 2, 14, 14, 16), Block.makeCuboidShape(0, 12, 3, 13, 13, 16),
					Block.makeCuboidShape(0, 11, 4, 12, 12, 16), Block.makeCuboidShape(0, 10, 5, 11, 11, 16),
					Block.makeCuboidShape(0, 9, 6, 10, 10, 16), Block.makeCuboidShape(0, 8, 7, 9, 9, 16),
					Block.makeCuboidShape(0, 7, 8, 8, 8, 16), Block.makeCuboidShape(0, 6, 9, 7, 7, 16),
					Block.makeCuboidShape(0, 5, 10, 6, 6, 16), Block.makeCuboidShape(0, 4, 11, 5, 5, 16),
					Block.makeCuboidShape(0, 3, 12, 4, 4, 16), Block.makeCuboidShape(0, 2, 13, 3, 3, 16),
					Block.makeCuboidShape(0, 1, 14, 2, 2, 16), Block.makeCuboidShape(0, 0, 15, 1, 1, 16))
			.reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_SW_T = Stream
			.of(Block.makeCuboidShape(0, 15, 0, 16, 16, 16), Block.makeCuboidShape(1, 14, 0, 16, 15, 15),
					Block.makeCuboidShape(2, 13, 0, 16, 14, 14), Block.makeCuboidShape(3, 12, 0, 16, 13, 13),
					Block.makeCuboidShape(4, 11, 0, 16, 12, 12), Block.makeCuboidShape(5, 10, 0, 16, 11, 11),
					Block.makeCuboidShape(6, 9, 0, 16, 10, 10), Block.makeCuboidShape(7, 8, 0, 16, 9, 9),
					Block.makeCuboidShape(8, 7, 0, 16, 8, 8), Block.makeCuboidShape(9, 6, 0, 16, 7, 7),
					Block.makeCuboidShape(10, 5, 0, 16, 6, 6), Block.makeCuboidShape(11, 4, 0, 16, 5, 5),
					Block.makeCuboidShape(12, 3, 0, 16, 4, 4), Block.makeCuboidShape(13, 2, 0, 16, 3, 3),
					Block.makeCuboidShape(14, 1, 0, 16, 2, 2), Block.makeCuboidShape(15, 0, 0, 16, 1, 1))
			.reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_SE_T = Stream
			.of(Block.makeCuboidShape(0, 15, 0, 16, 16, 16), Block.makeCuboidShape(0, 14, 0, 15, 15, 15),
					Block.makeCuboidShape(0, 13, 0, 14, 14, 14), Block.makeCuboidShape(0, 12, 0, 13, 13, 13),
					Block.makeCuboidShape(0, 11, 0, 12, 12, 12), Block.makeCuboidShape(0, 10, 0, 11, 11, 11),
					Block.makeCuboidShape(0, 9, 0, 10, 10, 10), Block.makeCuboidShape(0, 8, 0, 9, 9, 9),
					Block.makeCuboidShape(0, 7, 0, 8, 8, 8), Block.makeCuboidShape(0, 6, 0, 7, 7, 7),
					Block.makeCuboidShape(0, 5, 0, 6, 6, 6), Block.makeCuboidShape(0, 4, 0, 5, 5, 5),
					Block.makeCuboidShape(0, 3, 0, 4, 4, 4), Block.makeCuboidShape(0, 2, 0, 3, 3, 3),
					Block.makeCuboidShape(0, 1, 0, 2, 2, 2), Block.makeCuboidShape(0, 0, 0, 1, 1, 1))
			.reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_NW_I = Stream.of(Block.makeCuboidShape(0, 0, 0, 16, 1, 16),
			Block.makeCuboidShape(0, 1, 15, 16, 16, 16), Block.makeCuboidShape(0, 1, 14, 15, 15, 15),
			Block.makeCuboidShape(0, 1, 13, 14, 14, 14), Block.makeCuboidShape(0, 1, 12, 13, 13, 13),
			Block.makeCuboidShape(0, 1, 11, 12, 12, 12), Block.makeCuboidShape(0, 1, 10, 11, 11, 11),
			Block.makeCuboidShape(0, 1, 9, 10, 10, 10), Block.makeCuboidShape(0, 1, 8, 9, 9, 9),
			Block.makeCuboidShape(0, 1, 7, 8, 8, 8), Block.makeCuboidShape(0, 1, 6, 7, 7, 7),
			Block.makeCuboidShape(0, 1, 5, 6, 6, 6), Block.makeCuboidShape(0, 1, 4, 5, 5, 5),
			Block.makeCuboidShape(0, 1, 3, 4, 4, 4), Block.makeCuboidShape(0, 1, 2, 3, 3, 3),
			Block.makeCuboidShape(0, 1, 1, 2, 2, 2), Block.makeCuboidShape(1, 1, 0, 2, 2, 1),
			Block.makeCuboidShape(2, 1, 0, 3, 3, 2), Block.makeCuboidShape(3, 1, 0, 4, 4, 3),
			Block.makeCuboidShape(4, 1, 0, 5, 5, 4), Block.makeCuboidShape(5, 1, 0, 6, 6, 5),
			Block.makeCuboidShape(6, 1, 0, 7, 7, 6), Block.makeCuboidShape(7, 1, 0, 8, 8, 7),
			Block.makeCuboidShape(8, 1, 0, 9, 9, 8), Block.makeCuboidShape(9, 1, 0, 10, 10, 9),
			Block.makeCuboidShape(10, 1, 0, 11, 11, 10), Block.makeCuboidShape(11, 1, 0, 12, 12, 11),
			Block.makeCuboidShape(12, 1, 0, 13, 13, 12), Block.makeCuboidShape(13, 1, 0, 14, 14, 13),
			Block.makeCuboidShape(14, 1, 0, 15, 15, 14), Block.makeCuboidShape(15, 1, 0, 16, 16, 15))
			.reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_NE_I = Stream.of(Block.makeCuboidShape(0, 0, 0, 16, 1, 16),
			Block.makeCuboidShape(0, 1, 0, 1, 16, 16), Block.makeCuboidShape(1, 1, 0, 2, 15, 15),
			Block.makeCuboidShape(2, 1, 0, 3, 14, 14), Block.makeCuboidShape(3, 1, 0, 4, 13, 13),
			Block.makeCuboidShape(4, 1, 0, 5, 12, 12), Block.makeCuboidShape(5, 1, 0, 6, 11, 11),
			Block.makeCuboidShape(6, 1, 0, 7, 10, 10), Block.makeCuboidShape(7, 1, 0, 8, 9, 9),
			Block.makeCuboidShape(8, 1, 0, 9, 8, 8), Block.makeCuboidShape(9, 1, 0, 10, 7, 7),
			Block.makeCuboidShape(10, 1, 0, 11, 6, 6), Block.makeCuboidShape(11, 1, 0, 12, 5, 5),
			Block.makeCuboidShape(12, 1, 0, 13, 4, 4), Block.makeCuboidShape(13, 1, 0, 14, 3, 3),
			Block.makeCuboidShape(14, 1, 0, 15, 2, 2), Block.makeCuboidShape(15, 1, 1, 16, 2, 2),
			Block.makeCuboidShape(14, 1, 2, 16, 3, 3), Block.makeCuboidShape(13, 1, 3, 16, 4, 4),
			Block.makeCuboidShape(12, 1, 4, 16, 5, 5), Block.makeCuboidShape(11, 1, 5, 16, 6, 6),
			Block.makeCuboidShape(10, 1, 6, 16, 7, 7), Block.makeCuboidShape(9, 1, 7, 16, 8, 8),
			Block.makeCuboidShape(8, 1, 8, 16, 9, 9), Block.makeCuboidShape(7, 1, 9, 16, 10, 10),
			Block.makeCuboidShape(6, 1, 10, 16, 11, 11), Block.makeCuboidShape(5, 1, 11, 16, 12, 12),
			Block.makeCuboidShape(4, 1, 12, 16, 13, 13), Block.makeCuboidShape(3, 1, 13, 16, 14, 14),
			Block.makeCuboidShape(2, 1, 14, 16, 15, 15), Block.makeCuboidShape(1, 1, 15, 16, 16, 16))
			.reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_SW_I = Stream.of(Block.makeCuboidShape(0, 0, 0, 16, 1, 16),
			Block.makeCuboidShape(15, 1, 0, 16, 16, 16), Block.makeCuboidShape(14, 1, 1, 15, 15, 16),
			Block.makeCuboidShape(13, 1, 2, 14, 14, 16), Block.makeCuboidShape(12, 1, 3, 13, 13, 16),
			Block.makeCuboidShape(11, 1, 4, 12, 12, 16), Block.makeCuboidShape(10, 1, 5, 11, 11, 16),
			Block.makeCuboidShape(9, 1, 6, 10, 10, 16), Block.makeCuboidShape(8, 1, 7, 9, 9, 16),
			Block.makeCuboidShape(7, 1, 8, 8, 8, 16), Block.makeCuboidShape(6, 1, 9, 7, 7, 16),
			Block.makeCuboidShape(5, 1, 10, 6, 6, 16), Block.makeCuboidShape(4, 1, 11, 5, 5, 16),
			Block.makeCuboidShape(3, 1, 12, 4, 4, 16), Block.makeCuboidShape(2, 1, 13, 3, 3, 16),
			Block.makeCuboidShape(1, 1, 14, 2, 2, 16), Block.makeCuboidShape(0, 1, 14, 1, 2, 15),
			Block.makeCuboidShape(0, 1, 13, 2, 3, 14), Block.makeCuboidShape(0, 1, 12, 3, 4, 13),
			Block.makeCuboidShape(0, 1, 11, 4, 5, 12), Block.makeCuboidShape(0, 1, 10, 5, 6, 11),
			Block.makeCuboidShape(0, 1, 9, 6, 7, 10), Block.makeCuboidShape(0, 1, 8, 7, 8, 9),
			Block.makeCuboidShape(0, 1, 7, 8, 9, 8), Block.makeCuboidShape(0, 1, 6, 9, 10, 7),
			Block.makeCuboidShape(0, 1, 5, 10, 11, 6), Block.makeCuboidShape(0, 1, 4, 11, 12, 5),
			Block.makeCuboidShape(0, 1, 3, 12, 13, 4), Block.makeCuboidShape(0, 1, 2, 13, 14, 3),
			Block.makeCuboidShape(0, 1, 1, 14, 15, 2), Block.makeCuboidShape(0, 1, 0, 15, 16, 1)).reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_SE_I = Stream.of(Block.makeCuboidShape(0, 0, 0, 16, 1, 16),
			Block.makeCuboidShape(0, 1, 0, 16, 16, 1), Block.makeCuboidShape(1, 1, 1, 16, 15, 2),
			Block.makeCuboidShape(2, 1, 2, 16, 14, 3), Block.makeCuboidShape(3, 1, 3, 16, 13, 4),
			Block.makeCuboidShape(4, 1, 4, 16, 12, 5), Block.makeCuboidShape(5, 1, 5, 16, 11, 6),
			Block.makeCuboidShape(6, 1, 6, 16, 10, 7), Block.makeCuboidShape(7, 1, 7, 16, 9, 8),
			Block.makeCuboidShape(8, 1, 8, 16, 8, 9), Block.makeCuboidShape(9, 1, 9, 16, 7, 10),
			Block.makeCuboidShape(10, 1, 10, 16, 6, 11), Block.makeCuboidShape(11, 1, 11, 16, 5, 12),
			Block.makeCuboidShape(12, 1, 12, 16, 4, 13), Block.makeCuboidShape(13, 1, 13, 16, 3, 14),
			Block.makeCuboidShape(14, 1, 14, 16, 2, 15), Block.makeCuboidShape(14, 1, 15, 15, 2, 16),
			Block.makeCuboidShape(13, 1, 14, 14, 3, 16), Block.makeCuboidShape(12, 1, 13, 13, 4, 16),
			Block.makeCuboidShape(11, 1, 12, 12, 5, 16), Block.makeCuboidShape(10, 1, 11, 11, 6, 16),
			Block.makeCuboidShape(9, 1, 10, 10, 7, 16), Block.makeCuboidShape(8, 1, 9, 9, 8, 16),
			Block.makeCuboidShape(7, 1, 8, 8, 9, 16), Block.makeCuboidShape(6, 1, 7, 7, 10, 16),
			Block.makeCuboidShape(5, 1, 6, 6, 11, 16), Block.makeCuboidShape(4, 1, 5, 5, 12, 16),
			Block.makeCuboidShape(3, 1, 4, 4, 13, 16), Block.makeCuboidShape(2, 1, 3, 3, 14, 16),
			Block.makeCuboidShape(1, 1, 2, 2, 15, 16), Block.makeCuboidShape(0, 1, 1, 1, 16, 16)).reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_NW_I_T = Stream.of(Block.makeCuboidShape(0, 15, 0, 16, 16, 16),
			Block.makeCuboidShape(15, 0, 0, 16, 15, 16), Block.makeCuboidShape(14, 1, 0, 15, 15, 15),
			Block.makeCuboidShape(13, 2, 0, 14, 15, 14), Block.makeCuboidShape(12, 3, 0, 13, 15, 13),
			Block.makeCuboidShape(11, 4, 0, 12, 15, 12), Block.makeCuboidShape(10, 5, 0, 11, 15, 11),
			Block.makeCuboidShape(9, 6, 0, 10, 15, 10), Block.makeCuboidShape(8, 7, 0, 9, 15, 9),
			Block.makeCuboidShape(7, 8, 0, 8, 15, 8), Block.makeCuboidShape(6, 9, 0, 7, 15, 7),
			Block.makeCuboidShape(5, 10, 0, 6, 15, 6), Block.makeCuboidShape(4, 11, 0, 5, 15, 5),
			Block.makeCuboidShape(3, 12, 0, 4, 15, 4), Block.makeCuboidShape(2, 13, 0, 3, 15, 3),
			Block.makeCuboidShape(1, 14, 0, 2, 15, 2), Block.makeCuboidShape(0, 14, 1, 1, 15, 2),
			Block.makeCuboidShape(0, 13, 2, 2, 15, 3), Block.makeCuboidShape(0, 12, 3, 3, 15, 4),
			Block.makeCuboidShape(0, 11, 4, 4, 15, 5), Block.makeCuboidShape(0, 10, 5, 5, 15, 6),
			Block.makeCuboidShape(0, 9, 6, 6, 15, 7), Block.makeCuboidShape(0, 8, 7, 7, 15, 8),
			Block.makeCuboidShape(0, 7, 8, 8, 15, 9), Block.makeCuboidShape(0, 6, 9, 9, 15, 10),
			Block.makeCuboidShape(0, 5, 10, 10, 15, 11), Block.makeCuboidShape(0, 4, 11, 11, 15, 12),
			Block.makeCuboidShape(0, 3, 12, 12, 15, 13), Block.makeCuboidShape(0, 2, 13, 13, 15, 14),
			Block.makeCuboidShape(0, 1, 14, 14, 15, 15), Block.makeCuboidShape(0, 0, 15, 15, 15, 16))
			.reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_NE_I_T = Stream.of(Block.makeCuboidShape(0, 15, 0, 16, 16, 16),
			Block.makeCuboidShape(0, 0, 15, 16, 15, 16), Block.makeCuboidShape(1, 1, 14, 16, 15, 15),
			Block.makeCuboidShape(2, 2, 13, 16, 15, 14), Block.makeCuboidShape(3, 3, 12, 16, 15, 13),
			Block.makeCuboidShape(4, 4, 11, 16, 15, 12), Block.makeCuboidShape(5, 5, 10, 16, 15, 11),
			Block.makeCuboidShape(6, 6, 9, 16, 15, 10), Block.makeCuboidShape(7, 7, 8, 16, 15, 9),
			Block.makeCuboidShape(8, 8, 7, 16, 15, 8), Block.makeCuboidShape(9, 9, 6, 16, 15, 7),
			Block.makeCuboidShape(10, 10, 5, 16, 15, 6), Block.makeCuboidShape(11, 11, 4, 16, 15, 5),
			Block.makeCuboidShape(12, 12, 3, 16, 15, 4), Block.makeCuboidShape(13, 13, 2, 16, 15, 3),
			Block.makeCuboidShape(14, 14, 1, 16, 15, 2), Block.makeCuboidShape(14, 14, 0, 15, 15, 1),
			Block.makeCuboidShape(13, 13, 0, 14, 15, 2), Block.makeCuboidShape(12, 12, 0, 13, 15, 3),
			Block.makeCuboidShape(11, 11, 0, 12, 15, 4), Block.makeCuboidShape(10, 10, 0, 11, 15, 5),
			Block.makeCuboidShape(9, 9, 0, 10, 15, 6), Block.makeCuboidShape(8, 8, 0, 9, 15, 7),
			Block.makeCuboidShape(7, 7, 0, 8, 15, 8), Block.makeCuboidShape(6, 6, 0, 7, 15, 9),
			Block.makeCuboidShape(5, 5, 0, 6, 15, 10), Block.makeCuboidShape(4, 4, 0, 5, 15, 11),
			Block.makeCuboidShape(3, 3, 0, 4, 15, 12), Block.makeCuboidShape(2, 2, 0, 3, 15, 13),
			Block.makeCuboidShape(1, 1, 0, 2, 15, 14), Block.makeCuboidShape(0, 0, 0, 1, 15, 15)).reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_SW_I_T = Stream.of(Block.makeCuboidShape(0, 15, 0, 16, 16, 16),
			Block.makeCuboidShape(0, 0, 0, 16, 15, 1), Block.makeCuboidShape(0, 1, 1, 15, 15, 2),
			Block.makeCuboidShape(0, 2, 2, 14, 15, 3), Block.makeCuboidShape(0, 3, 3, 13, 15, 4),
			Block.makeCuboidShape(0, 4, 4, 12, 15, 5), Block.makeCuboidShape(0, 5, 5, 11, 15, 6),
			Block.makeCuboidShape(0, 6, 6, 10, 15, 7), Block.makeCuboidShape(0, 7, 7, 9, 15, 8),
			Block.makeCuboidShape(0, 8, 8, 8, 15, 9), Block.makeCuboidShape(0, 9, 9, 7, 15, 10),
			Block.makeCuboidShape(0, 10, 10, 6, 15, 11), Block.makeCuboidShape(0, 11, 11, 5, 15, 12),
			Block.makeCuboidShape(0, 12, 12, 4, 15, 13), Block.makeCuboidShape(0, 13, 13, 3, 15, 14),
			Block.makeCuboidShape(0, 14, 14, 2, 15, 15), Block.makeCuboidShape(1, 14, 15, 2, 15, 16),
			Block.makeCuboidShape(2, 13, 14, 3, 15, 16), Block.makeCuboidShape(3, 12, 13, 4, 15, 16),
			Block.makeCuboidShape(4, 11, 12, 5, 15, 16), Block.makeCuboidShape(5, 10, 11, 6, 15, 16),
			Block.makeCuboidShape(6, 9, 10, 7, 15, 16), Block.makeCuboidShape(7, 8, 9, 8, 15, 16),
			Block.makeCuboidShape(8, 7, 8, 9, 15, 16), Block.makeCuboidShape(9, 6, 7, 10, 15, 16),
			Block.makeCuboidShape(10, 5, 6, 11, 15, 16), Block.makeCuboidShape(11, 4, 5, 12, 15, 16),
			Block.makeCuboidShape(12, 3, 4, 13, 15, 16), Block.makeCuboidShape(13, 2, 3, 14, 15, 16),
			Block.makeCuboidShape(14, 1, 2, 15, 15, 16), Block.makeCuboidShape(15, 0, 1, 16, 15, 16))
			.reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	protected static final VoxelShape SHAPE_SE_I_T = Stream.of(Block.makeCuboidShape(0, 15, 0, 16, 16, 16),
			Block.makeCuboidShape(0, 0, 0, 1, 15, 16), Block.makeCuboidShape(1, 1, 1, 2, 15, 16),
			Block.makeCuboidShape(2, 2, 2, 3, 15, 16), Block.makeCuboidShape(3, 3, 3, 4, 15, 16),
			Block.makeCuboidShape(4, 4, 4, 5, 15, 16), Block.makeCuboidShape(5, 5, 5, 6, 15, 16),
			Block.makeCuboidShape(6, 6, 6, 7, 15, 16), Block.makeCuboidShape(7, 7, 7, 8, 15, 16),
			Block.makeCuboidShape(8, 8, 8, 9, 15, 16), Block.makeCuboidShape(9, 9, 9, 10, 15, 16),
			Block.makeCuboidShape(10, 10, 10, 11, 15, 16), Block.makeCuboidShape(11, 11, 11, 12, 15, 16),
			Block.makeCuboidShape(12, 12, 12, 13, 15, 16), Block.makeCuboidShape(13, 13, 13, 14, 15, 16),
			Block.makeCuboidShape(14, 14, 14, 15, 15, 16), Block.makeCuboidShape(15, 14, 14, 16, 15, 15),
			Block.makeCuboidShape(14, 13, 13, 16, 15, 14), Block.makeCuboidShape(13, 12, 12, 16, 15, 13),
			Block.makeCuboidShape(12, 11, 11, 16, 15, 12), Block.makeCuboidShape(11, 10, 10, 16, 15, 11),
			Block.makeCuboidShape(10, 9, 9, 16, 15, 10), Block.makeCuboidShape(9, 8, 8, 16, 15, 9),
			Block.makeCuboidShape(8, 7, 7, 16, 15, 8), Block.makeCuboidShape(7, 6, 6, 16, 15, 7),
			Block.makeCuboidShape(6, 5, 5, 16, 15, 6), Block.makeCuboidShape(5, 4, 4, 16, 15, 5),
			Block.makeCuboidShape(4, 3, 3, 16, 15, 4), Block.makeCuboidShape(3, 2, 2, 16, 15, 3),
			Block.makeCuboidShape(2, 1, 1, 16, 15, 2), Block.makeCuboidShape(1, 0, 0, 16, 15, 1)).reduce((v1, v2) -> {
				return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);
			}).get();

	// protected static final VoxelShape SHAPE_NEW = SHAPE_N.rotate();

	private final Block modelBlock;
	private final BlockState modelState;

	// Forge: Use the other constructor that takes a Supplier
	@Deprecated
	protected SlopeBlock(BlockState state, Block.Properties properties) {
		super(properties);
		this.setDefaultState(this.stateContainer.getBaseState().with(FACING, Direction.NORTH).with(HALF, Half.BOTTOM)
				.with(SHAPE, StairsShape.STRAIGHT).with(WATERLOGGED, Boolean.valueOf(false)));
		this.modelBlock = state.getBlock();
		this.modelState = state;
		this.stateSupplier = () -> state;
	}

	public SlopeBlock(java.util.function.Supplier<BlockState> state, Block.Properties properties) {
		super(properties);
		this.setDefaultState(this.stateContainer.getBaseState().with(FACING, Direction.NORTH).with(HALF, Half.BOTTOM)
				.with(SHAPE, StairsShape.STRAIGHT).with(WATERLOGGED, Boolean.valueOf(false)));
		this.modelBlock = Blocks.AIR; // These are unused, fields are redirected
		this.modelState = Blocks.AIR.getDefaultState();
		this.stateSupplier = state;
	}

	public boolean isTransparent(BlockState state) {
		return true;
	}

	@Override
	public VoxelShape getShape(BlockState stateIn, IBlockReader worldIn, BlockPos posIn, ISelectionContext contextIn) {
		if (stateIn.get(HALF) == Half.TOP) {// 置于顶部
			if (stateIn.get(SHAPE) == StairsShape.STRAIGHT) {
				switch (stateIn.get(FACING)) {
				case NORTH:
					return SHAPE_N_T;
				case SOUTH:
					return SHAPE_S_T;
				case EAST:
					return SHAPE_E_T;
				case WEST:
					return SHAPE_W_T;
				default:
					return SHAPE_N_T;
				}
			} else if (stateIn.get(SHAPE) == StairsShape.OUTER_LEFT) {
				switch (stateIn.get(FACING)) {
				case NORTH:
					return SHAPE_NW_T;
				case SOUTH:
					return SHAPE_SE_T;
				case EAST:
					return SHAPE_NE_T;
				case WEST:
					return SHAPE_SW_T;
				default:
					return SHAPE_N_T;
				}
			} else if (stateIn.get(SHAPE) == StairsShape.OUTER_RIGHT) {
				switch (stateIn.get(FACING)) {
				case NORTH:
					return SHAPE_NE_T;
				case SOUTH:
					return SHAPE_SW_T;
				case EAST:
					return SHAPE_SE_T;
				case WEST:
					return SHAPE_NW_T;
				default:
					return SHAPE_N_T;
				}
			} else if (stateIn.get(SHAPE) == StairsShape.INNER_LEFT) {
				switch (stateIn.get(FACING)) {
				case NORTH:
					return SHAPE_NW_I_T;
				case SOUTH:
					return SHAPE_SE_I_T;
				case EAST:
					return SHAPE_NE_I_T;
				case WEST:
					return SHAPE_SW_I_T;
				default:
					return SHAPE_N_T;
				}
			} else {
				switch (stateIn.get(FACING)) {
				case NORTH:
					return SHAPE_NE_I_T;
				case SOUTH:
					return SHAPE_SW_I_T;
				case EAST:
					return SHAPE_SE_I_T;
				case WEST:
					return SHAPE_NW_I_T;
				default:
					return SHAPE_N_T;
				}
			}
		} else {// 置于地面
			if (stateIn.get(SHAPE) == StairsShape.STRAIGHT) {
				switch (stateIn.get(FACING)) {
				case NORTH:
					return SHAPE_N;
				case SOUTH:
					return SHAPE_S;
				case EAST:
					return SHAPE_E;
				case WEST:
					return SHAPE_W;
				default:
					return SHAPE_N;
				}
			} else if (stateIn.get(SHAPE) == StairsShape.OUTER_LEFT) {
				switch (stateIn.get(FACING)) {
				case NORTH:
					return SHAPE_NW;
				case SOUTH:
					return SHAPE_SE;
				case EAST:
					return SHAPE_NE;
				case WEST:
					return SHAPE_SW;
				default:
					return SHAPE_N;
				}
			} else if (stateIn.get(SHAPE) == StairsShape.OUTER_RIGHT) {
				switch (stateIn.get(FACING)) {
				case NORTH:
					return SHAPE_NE;
				case SOUTH:
					return SHAPE_SW;
				case EAST:
					return SHAPE_SE;
				case WEST:
					return SHAPE_NW;
				default:
					return SHAPE_N;
				}
			} else if (stateIn.get(SHAPE) == StairsShape.INNER_LEFT) {
				switch (stateIn.get(FACING)) {
				case NORTH:
					return SHAPE_NW_I;
				case SOUTH:
					return SHAPE_SE_I;
				case EAST:
					return SHAPE_NE_I;
				case WEST:
					return SHAPE_SW_I;
				default:
					return SHAPE_N;
				}
			} else {
				switch (stateIn.get(FACING)) {
				case NORTH:
					return SHAPE_NE_I;
				case SOUTH:
					return SHAPE_SW_I;
				case EAST:
					return SHAPE_SE_I;
				case WEST:
					return SHAPE_NW_I;
				default:
					return SHAPE_N;
				}
			}
		}

	}

	/**
	 * Called periodically clientside on blocks near the player to show effects
	 * (like furnace fire particles). Note that this method is unrelated to
	 * {@link randomTick} and {@link #needsRandomTick}, and will always be called
	 * regardless of whether the block can receive random update ticks
	 */
	@OnlyIn(Dist.CLIENT)
	public void animateTick(BlockState stateIn, World worldIn, BlockPos pos, Random rand) {
		this.modelBlock.animateTick(stateIn, worldIn, pos, rand);
	}

	public void onBlockClicked(BlockState state, World worldIn, BlockPos pos, PlayerEntity player) {
		this.modelState.onBlockClicked(worldIn, pos, player);
	}

	/**
	 * Called after a player destroys this Block - the posiiton pos may no longer
	 * hold the state indicated.
	 */
	public void onPlayerDestroy(IWorld worldIn, BlockPos pos, BlockState state) {
		this.modelBlock.onPlayerDestroy(worldIn, pos, state);
	}

	/**
	 * Returns how much this block can resist explosions from the passed in entity.
	 */
	@SuppressWarnings("deprecation")
	public float getExplosionResistance() {
		return this.modelBlock.getExplosionResistance();
	}

	/**
	 * How many world ticks before ticking
	 */
	public int tickRate(IWorldReader worldIn) {
		return this.modelBlock.tickRate(worldIn);
	}

	@SuppressWarnings("deprecation")
	public void onBlockAdded(BlockState state, World worldIn, BlockPos pos, BlockState oldState, boolean isMoving) {
		if (state.getBlock() != state.getBlock()) {
			this.modelState.neighborChanged(worldIn, pos, Blocks.AIR, pos, false);
			this.modelBlock.onBlockAdded(this.modelState, worldIn, pos, oldState, false);
		}
	}

	public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) {
		if (state.getBlock() != newState.getBlock()) {
			this.modelState.onReplaced(worldIn, pos, newState, isMoving);
		}
	}

	/**
	 * Called when the given entity walks on this Block
	 */
	public void onEntityWalk(World worldIn, BlockPos pos, Entity entityIn) {
		this.modelBlock.onEntityWalk(worldIn, pos, entityIn);
	}

	@SuppressWarnings("deprecation")
	public void tick(BlockState state, ServerWorld worldIn, BlockPos pos, Random rand) {
		this.modelBlock.tick(state, worldIn, pos, rand);
	}

	public ActionResultType onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player,
			Hand handIn, BlockRayTraceResult hit) {
		return this.modelState.onBlockActivated(worldIn, player, handIn, hit);
	}

	/**
	 * Called when this Block is destroyed by an Explosion
	 */
	public void onExplosionDestroy(World worldIn, BlockPos pos, Explosion explosionIn) {
		this.modelBlock.onExplosionDestroy(worldIn, pos, explosionIn);
	}

	public BlockState getStateForPlacement(BlockItemUseContext context) {
		Direction direction = context.getFace();
		BlockPos blockpos = context.getPos();
		IFluidState ifluidstate = context.getWorld().getFluidState(blockpos);
		BlockState blockstate = this.getDefaultState()
				.with(FACING, context.getPlacementHorizontalFacing().getOpposite())
				.with(HALF,
						direction != Direction.DOWN && (direction == Direction.UP
								|| !(context.getHitVec().y - (double) blockpos.getY() > 0.5D)) ? Half.BOTTOM : Half.TOP)
				.with(WATERLOGGED, Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER));
		return blockstate.with(SHAPE, getShapeProperty(blockstate, context.getWorld(), blockpos));
	}

	/**
	 * Update the provided state given the provided neighbor facing and neighbor
	 * state, returning a new state. For example, fences make their connections to
	 * the passed in state if possible, and wet concrete powder immediately returns
	 * its solidified counterpart. Note that this method should ideally consider
	 * only the specific face passed in.
	 */
	@SuppressWarnings("deprecation")
	public BlockState updatePostPlacement(BlockState stateIn, Direction facing, BlockState facingState, IWorld worldIn,
			BlockPos currentPos, BlockPos facingPos) {
		if (stateIn.get(WATERLOGGED)) {
			worldIn.getPendingFluidTicks().scheduleTick(currentPos, Fluids.WATER, Fluids.WATER.getTickRate(worldIn));
		}

		return facing.getAxis().isHorizontal() ? stateIn.with(SHAPE, getShapeProperty(stateIn, worldIn, currentPos))
				: super.updatePostPlacement(stateIn, facing, facingState, worldIn, currentPos, facingPos);
	}

	/**
	 * Returns a stair shape property based on the surrounding stairs from the given
	 * blockstate and position
	 */
	private static StairsShape getShapeProperty(BlockState state, IBlockReader worldIn, BlockPos pos) {
		Direction direction = state.get(FACING);
		BlockState blockstate = worldIn.getBlockState(pos.offset(direction));
		if (isBlockStairs(blockstate) && state.get(HALF) == blockstate.get(HALF)) {
			Direction direction1 = blockstate.get(FACING);
			if (direction1.getAxis() != state.get(FACING).getAxis()
					&& isDifferentStairs(state, worldIn, pos, direction1.getOpposite())) {
				if (direction1 == direction.rotateYCCW()) {
					return StairsShape.INNER_LEFT;
				}

				return StairsShape.INNER_RIGHT;
			}
		}

		BlockState blockstate1 = worldIn.getBlockState(pos.offset(direction.getOpposite()));
		if (isBlockStairs(blockstate1) && state.get(HALF) == blockstate1.get(HALF)) {
			Direction direction2 = blockstate1.get(FACING);
			if (direction2.getAxis() != state.get(FACING).getAxis()
					&& isDifferentStairs(state, worldIn, pos, direction2)) {
				if (direction2 == direction.rotateYCCW()) {
					return StairsShape.OUTER_LEFT;
				}

				return StairsShape.OUTER_RIGHT;
			}
		}

		return StairsShape.STRAIGHT;
	}

	private static boolean isDifferentStairs(BlockState state, IBlockReader worldIn, BlockPos pos, Direction face) {
		BlockState blockstate = worldIn.getBlockState(pos.offset(face));
		return !isBlockStairs(blockstate) || blockstate.get(FACING) != state.get(FACING)
				|| blockstate.get(HALF) != state.get(HALF);
	}

	public static boolean isBlockStairs(BlockState state) {
		return state.getBlock() instanceof SlopeBlock;
	}

	/**
	 * Returns the blockstate with the given rotation from the passed blockstate. If
	 * inapplicable, returns the passed blockstate.
	 * 
	 * @deprecated call via {@link IBlockState#withRotation(Rotation)} whenever
	 *             possible. Implementing/overriding is fine.
	 */
	public BlockState rotate(BlockState state, Rotation rot) {
		return state.with(FACING, rot.rotate(state.get(FACING)));
	}

	/**
	 * Returns the blockstate with the given mirror of the passed blockstate. If
	 * inapplicable, returns the passed blockstate.
	 * 
	 * @deprecated call via {@link IBlockState#withMirror(Mirror)} whenever
	 *             possible. Implementing/overriding is fine.
	 */
	public BlockState mirror(BlockState state, Mirror mirrorIn) {
		Direction direction = state.get(FACING);
		StairsShape stairsshape = state.get(SHAPE);
		switch (mirrorIn) {
		case LEFT_RIGHT:
			if (direction.getAxis() == Direction.Axis.Z) {
				switch (stairsshape) {
				case INNER_LEFT:
					return state.rotate(Rotation.CLOCKWISE_180).with(SHAPE, StairsShape.INNER_RIGHT);
				case INNER_RIGHT:
					return state.rotate(Rotation.CLOCKWISE_180).with(SHAPE, StairsShape.INNER_LEFT);
				case OUTER_LEFT:
					return state.rotate(Rotation.CLOCKWISE_180).with(SHAPE, StairsShape.OUTER_RIGHT);
				case OUTER_RIGHT:
					return state.rotate(Rotation.CLOCKWISE_180).with(SHAPE, StairsShape.OUTER_LEFT);
				default:
					return state.rotate(Rotation.CLOCKWISE_180);
				}
			}
			break;
		case FRONT_BACK:
			if (direction.getAxis() == Direction.Axis.X) {
				switch (stairsshape) {
				case INNER_LEFT:
					return state.rotate(Rotation.CLOCKWISE_180).with(SHAPE, StairsShape.INNER_LEFT);
				case INNER_RIGHT:
					return state.rotate(Rotation.CLOCKWISE_180).with(SHAPE, StairsShape.INNER_RIGHT);
				case OUTER_LEFT:
					return state.rotate(Rotation.CLOCKWISE_180).with(SHAPE, StairsShape.OUTER_RIGHT);
				case OUTER_RIGHT:
					return state.rotate(Rotation.CLOCKWISE_180).with(SHAPE, StairsShape.OUTER_LEFT);
				case STRAIGHT:
					return state.rotate(Rotation.CLOCKWISE_180);
				}
			}
		}

		return super.mirror(state, mirrorIn);
	}

	protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder) {
		builder.add(FACING, HALF, SHAPE, WATERLOGGED);
	}

	@SuppressWarnings("deprecation")
	public IFluidState getFluidState(BlockState state) {
		return state.get(WATERLOGGED) ? Fluids.WATER.getStillFluidState(false) : super.getFluidState(state);
	}

	public boolean allowsMovement(BlockState state, IBlockReader worldIn, BlockPos pos, PathType type) {
		return false;
	}

	private final java.util.function.Supplier<BlockState> stateSupplier;

	private Block getModelBlock() {
		return getModelState().getBlock();
	}

	private BlockState getModelState() {
		return stateSupplier.get();
	}

// 活塞推动支持
	public PushReaction getPushReaction(BlockState state) {
		return PushReaction.NORMAL;
	}
}